package it.michaellinker.msr.web.filter;

import it.michaellinker.msr.web.util.metric.counter.BooleanCounter;
import it.michaellinker.msr.web.util.metric.counter.RequestCounter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpMethod;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;
import java.util.List;
import java.util.Map;

@Slf4j
@Component
@Order(1)
public class RequestCounterFilter extends OncePerRequestFilter {
    @Value("${filter.counter.pattern}")
    private List<String> pattern;
    @Value("${filter.counter.format.value}")
    private String formatValue;
    @Value("${filter.counter.format.time}")
    private String formatTime;
    @Value("${filter.counter.format.concat}")
    private String formatConcat;
    @Value("${filter.counter.period.min}")
    private Integer periodMin;
    @Value("${filter.counter.period.sec}")
    private Integer periodSec;
    private static final long COUNTER_DEFAULT_VALUE = 0L;
    private static final String GET_METHOD = HttpMethod.GET.name();
    private static final String POST_METHOD = HttpMethod.POST.name();
    private final RequestCounter<String> counter = new BooleanCounter<>(GET_METHOD, POST_METHOD);

    @Override
    protected boolean shouldNotFilter(HttpServletRequest request) {
        String path = request.getServletPath();
        return pattern.stream()
                .noneMatch(path::contains);
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request,
                                    HttpServletResponse response,
                                    FilterChain filterChain) throws ServletException, IOException {
        counter.count(request.getMethod());
        filterChain.doFilter(request, response);
    }

    @Scheduled(fixedRateString = "${filter.counter.period.calculatedMs}")
    public void countRequestsPerSecond() {
        Map<String, Long> counterMap = counter.getResult();
        Long getCounter = counterMap.getOrDefault(GET_METHOD, COUNTER_DEFAULT_VALUE);
        Long postCounter = counterMap.getOrDefault(POST_METHOD, COUNTER_DEFAULT_VALUE);
        log.info(String.format(formatConcat,
                String.format(formatValue, getCounter, postCounter, (getCounter + postCounter)),
                String.format(formatTime, periodMin, periodSec))
        );
    }
}
